package com.tm.seurity.filter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tm.result.Result;
import com.tm.result.ResultCode;
import com.tm.seurity.domain.User;
import com.tm.utils.JwtTokenUtil;
import com.tm.utils.ResponseUtil;
import com.tm.utils.SpringUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by lichuan on 2022-09-24.
 */
public class JwtAuthenticationTokenFilter extends BasicAuthenticationFilter {

    public JwtAuthenticationTokenFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 处理 token拦截
        /**
         * 1. 获取token
         * 2. 校验token是否在redis中存在
         * 3. 解析token获取用户信息
         * 4. 将用户信息放入到当前请求上下文
         * 5. 执行下一个拦截器
         */
        String authorization = request.getHeader("Authorization");
        if (!StringUtils.isEmpty(authorization)) {
            String[] split = authorization.split(" ");
            String token = split[1];
            RedisTemplate bean = SpringUtil.getBean("redisTemplate");
            try {

                if (bean.hasKey(token)) {
                    //TODO 解析token
                    Claims claims = JwtTokenUtil.parseToken(token);
                    String userId = claims.getId();
                    String username = claims.getSubject();
                    if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(userId)) {
                        // 获取角色
                        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
                        String authoritiesStr = claims.get("authorities").toString();
                        if (!StringUtils.isEmpty(authoritiesStr)) {
                            ObjectMapper objectMapper = new ObjectMapper();
                            JsonNode jsonNode = objectMapper.readTree(authoritiesStr);
                            Iterator<JsonNode> elements = jsonNode.elements();
                            while (elements.hasNext()) {
                                JsonNode next = elements.next();
                                authorities.add(new SimpleGrantedAuthority(next.path("authority").asText()));
                            }
                        }
                        //组装参数
                        User user = new User();
                        user.setUsername(claims.getSubject());
                        user.setId(Long.parseLong(claims.getId()));
                        user.setAuthorities(authorities);
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, userId, authorities);
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                    bean.expire(token,3, TimeUnit.DAYS);
                }

            } catch (ExpiredJwtException e) {
                ResponseUtil.out(response, Result.error(ResultCode.TOKEN_HASH_EXPIRED));
            } catch (Exception e) {
                ResponseUtil.out(response, Result.error(ResultCode.TOKEN_IS_INVALID));
            }
        }
        System.out.println("处理token登陆拦截");
        chain.doFilter(request, response);
    }
}
